/*
Copyright 2017 yangchong211（github.com/yangchong211）

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.yc.video.player;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.StackLayout;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.global.resource.RawFileDescriptor;

import com.yc.kernel.factory.PlayerFactory;
import com.yc.kernel.inter.AbstractVideoPlayer;
import com.yc.kernel.inter.VideoPlayerListener;
import com.yc.kernel.utils.PlayerConstant;
import com.yc.kernel.utils.VideoLogUtils;
import com.yc.video.config.ConstantKeys;
import com.yc.video.config.VideoPlayerConfig;
import com.yc.video.controller.BaseVideoController;
import com.yc.video.surface.InterSurfaceView;
import com.yc.video.surface.SurfaceFactory;
import com.yc.video.tool.AttrValue;
import com.yc.video.tool.BaseToast;
import com.yc.video.tool.PlayerUtils;
import com.yc.video.tool.TextUtils;
import com.yc.video.tool.VideoException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * <pre>
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2018/11/9
 *     desc  : 播放器具体实现类
 *     revise:
 * </pre>
 */
public class VideoPlayer<P extends AbstractVideoPlayer> extends StackLayout
    implements InterVideoPlayer, VideoPlayerListener, Component.BindStateChangedListener, Component.FocusChangedListener {
    private Context mContext;
    /**
     * 播放器
     */
    protected P mMediaPlayer;
    /**
     * 实例化播放核心
     */
    protected PlayerFactory<P> mPlayerFactory;
    /**
     * 控制器
     */
    protected BaseVideoController mVideoController;
    /**
     * 真正承载播放器视图的容器
     */
    protected StackLayout mPlayerContainer;

    protected InterSurfaceView mRenderView;
    protected SurfaceFactory mRenderViewFactory;
    protected int mCurrentScreenScaleType;
    protected int[] mVideoSize = {0, 0};
    /**
     * 是否静音
     */
    protected boolean mIsMute;

    /**
     * 当前播放视频的地址
     */
    protected String mUrl;
    /**
     * 当前视频地址的请求头
     */
    protected Map<String, String> mHeaders;
    /**
     * assets文件
     */
    protected RawFileDescriptor mAssetFileDescriptor;
    /**
     * 当前正在播放视频的位置
     */
    protected long mCurrentPosition;
    /**
     * 当前播放器的状态
     * 比如：错误，开始播放，暂停播放，缓存中等等状态
     */
    protected int mCurrentPlayState = ConstantKeys.CurrentState.STATE_IDLE;
    /**
     * 播放模式，普通模式，小窗口模式，正常模式等等
     * 存在局限性：比如小窗口下的正在播放模式，那么mCurrentMode就是STATE_PLAYING，而不是MODE_TINY_WINDOW并存
     **/
    protected int mCurrentPlayerState = ConstantKeys.PlayMode.MODE_NORMAL;
    /**
     * 是否处于全屏状态,默认是false
     */
    protected boolean mIsFullScreen;
    /**
     * 是否处于小屏状态
     */
    protected boolean mIsTinyScreen;
    protected int[] mTinyScreenSize = {0, 0};
    /**
     * 监听系统中音频焦点改变
     */
    protected boolean mEnableAudioFocus;
    protected AudioFocusHelper mAudioFocusHelper;

    /**
     * OnStateChangeListener集合，保存了所有开发者设置的监听器
     */
    protected List<OnVideoStateListener> mOnStateChangeListeners;

    /**
     * 进度管理器，设置之后播放器会记录播放进度，以便下次播放恢复进度
     */
    protected ProgressManager mProgressManager;

    /**
     * 循环播放
     */
    protected boolean mIsLooping;

    /**
     * {@link #mPlayerContainer}背景色，默认黑色
     */
    private int mPlayerBackgroundColor;
    private ComponentContainer componentContainer;

    public VideoPlayer(Context context) {
        this(context, null);
    }

    public VideoPlayer(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    public VideoPlayer(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init(attrs);
    }

    private void init(AttrSet attrs) {
        BaseToast.init(mContext.getApplicationContext());
        initConfig(); // 读取全局配置
        initAttrs(attrs); // 读取xml中的配置，并综合全局配置
        initView();
    }

    private void initConfig() {
        VideoPlayerConfig config = VideoViewManager.getConfig();
        mEnableAudioFocus = config.mEnableAudioFocus;
        mProgressManager = config.mProgressManager;
        mPlayerFactory = config.mPlayerFactory;
        mCurrentScreenScaleType = config.mScreenScaleType;
        mRenderViewFactory = config.mRenderViewFactory;
        VideoLogUtils.setIsLog(config.mIsEnableLog); // 设置是否打印日志
    }

    /**
     * onAttachedToWindow方法ProxyVideoCacheManager
     * 是在Activity resume的时候被调用的，也就是activity对应的window被添加的时候，且每个view只会被调用一次，
     * 父view的调用在前，不论view的visibility状态都会被调用，适合做些view特定的初始化操作；
     * <p>
     * 主要做什么：适合初始化操作
     * <p>
     * 代码流程：
     * ActivityThread.handleResumeActivity()--->WindowManager.addView()--->WindowManagerImpl.addView()
     * -->WindowManagerGlobal.addView()--->root.setView(view, wparams, panelParentView)
     * --->host.dispatchAttachedToWindow()[具体代码在ViewRootImpl类中]
     *
     * @param component component
     */
    @Override
    public void onComponentBoundToWindow(Component component) {
        VideoLogUtils.d("onAttachedToWindow");
    }

    /**
     * onDetachedFromWindow方法
     * 是在Activity destroy的时候被调用的，也就是activity对应的window被删除的时候，且每个view只会被调用一次，
     * 父view的调用在后，也不论view的visibility状态都会被调用，适合做最后的清理操作；
     * <p>
     * 主要做什么：适合销毁清理操作
     * <p>
     * 代码流程：
     * ActivityThread.handleDestroyActivity() --> WindowManager.removeViewImmediate() -->
     * WindowManagerGlobal.removeViewLocked()方法 —> ViewRootImpl.die() --> doDie() -->
     * ViewRootImpl.dispatchDetachedFromWindow()
     *
     * @param component component
     */
    @Override
    public void onComponentUnboundFromWindow(Component component) {
        VideoLogUtils.d("onDetachedFromWindow");
        if (mVideoController != null) {
            mVideoController.destroy();
        }
        // onDetachedFromWindow方法是在Activity destroy的时候被调用的，也就是act对应的window被删除的时候，
        // 且每个view只会被调用一次，父view的调用在后，也不论view的visibility状态都会被调用，适合做最后的清理操作
        // 防止开发者没有在onDestroy中没有做销毁视频的优化
        release();
    }

    /**
     * View所在窗口获取焦点或者失去焦点时调用
     *
     * @param component component
     * @param b 是否获取window焦点
     */
    @Override
    public void onFocusChange(Component component, boolean b) {
        if (b && mIsFullScreen) {
            // 重新获得焦点时保持全屏状态
            ComponentContainer decorView = VideoPlayerHelper.instance().getDecorView(mContext, mVideoController);
            VideoPlayerHelper.instance().hideSysBar(decorView, mContext, mVideoController);
        }
    }

    /**
     * 初始化
     *
     * @param attrs attrs
     */
    private void initAttrs(AttrSet attrs) {
        mEnableAudioFocus = AttrValue.get(attrs, "enableAudioFocus", mEnableAudioFocus);
        mIsLooping = AttrValue.get(attrs, "looping", false);
        mCurrentScreenScaleType = AttrValue.getDimension(attrs, "screenScaleType", mCurrentScreenScaleType);
        mPlayerBackgroundColor = AttrValue.get(attrs, "playerBackgroundColor",
            Color.BLACK).getValue();
    }

    /**
     * 初始化播放器视图
     */
    protected void initView() {
        mPlayerContainer = new StackLayout(getContext());
        ShapeElement background = new ShapeElement();
        background.setRgbColor(new RgbColor(RgbColor.fromArgbInt(mPlayerBackgroundColor)));
        mPlayerContainer.setBackground(background); // 设置背景颜色，目前设置为纯黑色
        ComponentContainer.LayoutConfig params = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            ComponentContainer.LayoutConfig.MATCH_PARENT);
        this.addComponent(mPlayerContainer, params); // 将布局添加到该视图中
    }

    /**
     * 设置控制器，传null表示移除控制器
     *
     * @param mediaController controller
     */
    public void setController(BaseVideoController mediaController) {
        if (mVideoController != null) {
            mPlayerContainer.removeComponent(mVideoController);
        }
        mVideoController = mediaController;
        if (mediaController != null) {
            mediaController.setMediaPlayer(this);
            ComponentContainer.LayoutConfig params = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT);
            mPlayerContainer.addComponent(mVideoController, params);
        }
    }

    /**
     * 开始播放，注意：调用此方法后必须调用{@link #release()}释放播放器，否则会导致内存泄漏
     */
    @Override
    public void start() {
        if (mVideoController == null) {
            // 在调用start方法前，请先初始化视频控制器，调用setController方法
            throw new VideoException(VideoException.CODE_NOT_SET_CONTROLLER,
                "Controller must not be null , please setController first");
        }
        boolean isStarted = false;
        if (isInIdleState() || isInStartAbortState()) {
            isStarted = startPlay();
        } else if (isInPlaybackState()) {
            startInPlaybackState();
            isStarted = true;
        }
        if (isStarted) {
            // mPlayerContainer.setKeepScreenOn(true);
            if (mAudioFocusHelper != null) {
                mAudioFocusHelper.requestFocus();
            }
        }
    }

    /**
     * 第一次播放
     *
     * @return 是否成功开始播放
     */
    protected boolean startPlay() {
        // 如果要显示移动网络提示则不继续播放
        if (showNetWarning()) {
            // 中止播放
            setPlayState(ConstantKeys.CurrentState.STATE_START_ABORT);
            return false;
        }
        // 监听音频焦点改变
        if (mEnableAudioFocus) {
            mAudioFocusHelper = new AudioFocusHelper(this);
        }
        // 读取播放进度
        if (mProgressManager != null) {
            mCurrentPosition = mProgressManager.getSavedProgress(mUrl);
        }
        initPlayer();
        addDisplay();
        startPrepare(false);
        return true;
    }

    /**
     * 初始化播放器
     */
    protected void initPlayer() {
        // 通过工厂模式创建对象
        mMediaPlayer = mPlayerFactory.createPlayer(mContext);
        mMediaPlayer.setPlayerEventListener(this);
        setInitOptions();
        mMediaPlayer.initPlayer();
        setOptions();
    }

    /**
     * 是否显示移动网络提示，可在Controller中配置
     *
     * @return return
     */
    protected boolean showNetWarning() {
        // 播放本地数据源时不检测网络
        if (VideoPlayerHelper.instance().isLocalDataSource(mUrl, mAssetFileDescriptor)) {
            return false;
        }
        return mVideoController != null && mVideoController.showNetWarning();
    }

    /**
     * 初始化之前的配置项
     */
    protected void setInitOptions() {
    }

    /**
     * 初始化之后的配置项
     */
    protected void setOptions() {
        // 设置是否循环播放
        mMediaPlayer.setLooping(mIsLooping);
    }

    /**
     * 初始化视频渲染View
     */
    protected void addDisplay() {
        if (mRenderView != null) {
            // 从容器中移除渲染view
            mPlayerContainer.removeComponent(mRenderView.getView());
            // 释放资源
            mRenderView.release();
        }
        // 创建TextureView对象
        mRenderView = mRenderViewFactory.createRenderView(mContext);
        // 绑定mMediaPlayer对象
        mRenderView.attachToPlayer(mMediaPlayer);
        // 添加渲染view到Container布局中
        ComponentContainer.LayoutConfig params = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            ComponentContainer.LayoutConfig.MATCH_PARENT, LayoutAlignment.CENTER);
        mPlayerContainer.addComponent(mRenderView.getView(), 0, params);
    }

    /**
     * 开始准备播放（直接播放）
     *
     * @param reset reset
     */
    protected void startPrepare(boolean reset) {
        if (reset) {
            mMediaPlayer.reset();
            setOptions(); // 重新设置option，media player reset之后，option会失效
            addDisplay();
        }
        if (prepareDataSource()) { // 播放数据是否设置成功
            mMediaPlayer.prepareAsync(); // 准备开始播放
            setPlayState(ConstantKeys.CurrentState.STATE_PREPARING); // 更改播放器的播放状态
            setPlayerState(isFullScreen() ? ConstantKeys.PlayMode.MODE_FULL_SCREEN : isTinyScreen() ? ConstantKeys.PlayMode.MODE_TINY_WINDOW : ConstantKeys.PlayMode.MODE_NORMAL); // 更改播放器播放模式状态
        }
    }

    /**
     * 设置播放数据
     *
     * @return 播放数据是否设置成功
     */
    protected boolean prepareDataSource() {
        if (mAssetFileDescriptor != null) {
            mMediaPlayer.setDataSource(mAssetFileDescriptor);
            return true;
        } else if (!TextUtils.isEmpty(mUrl)) {
            mMediaPlayer.setDataSource(mUrl, mHeaders);
            return true;
        }
        return false;
    }

    /**
     * 播放状态下开始播放
     */
    protected void startInPlaybackState() {
        mMediaPlayer.start();
        setPlayState(ConstantKeys.CurrentState.STATE_PLAYING);
    }

    /**
     * 暂停播放
     */
    @Override
    public void pause() {
        if ((mCurrentPlayState == ConstantKeys.CurrentState.STATE_PREPARING && mMediaPlayer != null) ||
            (isInPlaybackState() && mMediaPlayer.isPlaying())) {
            mMediaPlayer.pause();
            setPlayState(ConstantKeys.CurrentState.STATE_PAUSED);
            if (mAudioFocusHelper != null) {
                mAudioFocusHelper.abandonFocus();
            }
        }
    }

    /**
     * 继续播放
     */
    public void resume() {
        // home键再返回应用黑屏的bug， 需要重新设置surface
        if (mMediaPlayer != null) {
            // 重置renderView
            addDisplay();
            if (mRenderView != null) {
                mRenderView.setScaleType(mCurrentScreenScaleType);
                mRenderView.setVideoSize(mVideoSize[0], mVideoSize[1]);
            }
        }

        if (isInPlaybackState() && !mMediaPlayer.isPlaying()) {
            mMediaPlayer.start();
            setPlayState(ConstantKeys.CurrentState.STATE_PLAYING);
            if (mAudioFocusHelper != null) {
                mAudioFocusHelper.requestFocus();
            }
        }
    }

    /**
     * 释放播放器
     */
    public void release() {
        if (!isInIdleState()) {
            VideoPlayerConfig config = VideoViewManager.getConfig();
            if (config != null && config.mBuriedPointEvent != null) {
                // 退出视频播放
                config.mBuriedPointEvent.playerDestroy(mUrl);
                // 计算退出视频时候的进度
                long duration = getDuration();
                long currentPosition = getCurrentPosition();
                float progress = (currentPosition * 1.0f) / (duration * 1.0f);
                config.mBuriedPointEvent.playerOutProgress(mUrl, progress);
                config.mBuriedPointEvent.playerOutProgress(mUrl, duration, mCurrentPosition);
            }
            if (mMediaPlayer != null) { // 释放播放器
                mMediaPlayer.release();
                mMediaPlayer = null;
            }
            if (mRenderView != null) { // 释放renderView
                mPlayerContainer.removeComponent(mRenderView.getView());
                mRenderView.release();
                mRenderView = null;
            }
            if (mAssetFileDescriptor != null) { // 释放Assets资源
                try {
                    mAssetFileDescriptor.close();
                } catch (IOException e) {
                    VideoLogUtils.e(e.getMessage());
                }
            }
            if (mAudioFocusHelper != null) { // 关闭AudioFocus监听
                mAudioFocusHelper.abandonFocus();
                mAudioFocusHelper.release();
                mAudioFocusHelper = null;
            }
            saveProgress(); // 保存播放进度
            mCurrentPosition = 0; // 重置播放进度
            setPlayState(ConstantKeys.CurrentState.STATE_IDLE); // 切换转态
        }
    }

    /**
     * 保存播放进度
     */
    protected void saveProgress() {
        if (mProgressManager != null && mCurrentPosition > 0) {
            VideoLogUtils.d("saveProgress: " + mCurrentPosition);
            mProgressManager.saveProgress(mUrl, mCurrentPosition);
        }
    }

    /**
     * 是否处于播放状态
     *
     * @return return
     */
    public boolean isInPlaybackState() {
        return mMediaPlayer != null
            && mCurrentPlayState != ConstantKeys.CurrentState.STATE_ERROR
            && mCurrentPlayState != ConstantKeys.CurrentState.STATE_IDLE
            && mCurrentPlayState != ConstantKeys.CurrentState.STATE_PREPARING
            && mCurrentPlayState != ConstantKeys.CurrentState.STATE_START_ABORT
            && mCurrentPlayState != ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING;
    }

    /**
     * 是否处于未播放状态
     *
     * @return return
     */
    protected boolean isInIdleState() {
        return mCurrentPlayState == ConstantKeys.CurrentState.STATE_IDLE;
    }

    /**
     * 播放中止状态
     *
     * @return return
     */
    private boolean isInStartAbortState() {
        return mCurrentPlayState == ConstantKeys.CurrentState.STATE_START_ABORT;
    }

    /**
     * 重新播放
     *
     * @param resetPosition 是否从头开始播放
     */
    @Override
    public void replay(boolean resetPosition) {
        if (resetPosition) {
            mCurrentPosition = 0;
        }
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer = null;
        }
        initPlayer();
        // setSource后需要再调用setVideoSurface
        // 而此项目在SurfaceOps.Callback surfaceCreated方法中调用了setVideoSurface
        // 因此重新创建surface
        addDisplay();
        startPrepare(false);
    }

    /**
     * 获取视频总时长
     *
     * @return return
     */
    @Override
    public long getDuration() {
        if (isInPlaybackState()) {
            return mMediaPlayer.getDuration();
        }
        return 0;
    }

    /**
     * 获取当前播放的位置
     *
     * @return return
     */
    @Override
    public long getCurrentPosition() {
        if (isInPlaybackState()) {
            mCurrentPosition = mMediaPlayer.getCurrentPosition();
            return mCurrentPosition;
        }
        return 0;
    }

    /**
     * 调整播放进度
     *
     * @param pos 位置
     */
    @Override
    public void seekTo(long pos) {
        long seek;
        if (pos < 0) {
            VideoLogUtils.d("设置参数-------设置开始跳转播放位置不能小于0");
            seek = 0;
        } else {
            seek = pos;
        }
        if (isInPlaybackState()) {
            mMediaPlayer.seekTo(seek);
        }
    }

    /**
     * 是否处于播放状态
     *
     * @return return
     */
    @Override
    public boolean isPlaying() {
        return isInPlaybackState() && mMediaPlayer.isPlaying();
    }

    /**
     * 获取当前缓冲百分比
     *
     * @return return
     */
    @Override
    public int getBufferedPercentage() {
        return mMediaPlayer != null ? mMediaPlayer.getBufferedPercentage() : 0;
    }

    /**
     * 设置静音
     *
     * @param isMute isMute
     */
    @Override
    public void setMute(boolean isMute) {
        if (mMediaPlayer != null) {
            this.mIsMute = isMute;
            float volume = isMute ? 0.0f : 1.0f;
            mMediaPlayer.setVolume(volume, volume);
        }
    }

    /**
     * 是否处于静音状态
     *
     * @return return
     */
    @Override
    public boolean isMute() {
        return mIsMute;
    }

    /**
     * 视频播放出错回调
     *
     * @param type type
     * @param error error
     */
    @Override
    public void onError(@PlayerConstant.ErrorType int type, String error) {
        System.out.println(type + "--------视频播放出错回调------" + error);
        if (PlayerUtils.isConnected(mContext)) {
            if (type == PlayerConstant.ErrorType.TYPE_UNEXPECTED) {
                setPlayState(ConstantKeys.CurrentState.STATE_ERROR);
            } else if (type == PlayerConstant.ErrorType.TYPE_PARSE) {
                setPlayState(ConstantKeys.CurrentState.STATE_PARSE_ERROR);
            } else if (type == PlayerConstant.ErrorType.TYPE_SOURCE) {
                setPlayState(ConstantKeys.CurrentState.STATE_ERROR);
            } else {
                setPlayState(ConstantKeys.CurrentState.STATE_ERROR);
            }
        } else {
            setPlayState(ConstantKeys.CurrentState.STATE_NETWORK_ERROR);
        }
        setPlayState(ConstantKeys.CurrentState.STATE_ERROR);
        VideoPlayerConfig config = VideoViewManager.getConfig();
        if (config != null && config.mBuriedPointEvent != null) {
            // 相当于进入了视频页面
            if (PlayerUtils.isConnected(mContext)) {
                config.mBuriedPointEvent.onError(mUrl, false);
            } else {
                config.mBuriedPointEvent.onError(mUrl, true);
            }
        }
    }

    /**
     * 视频播放完成回调
     */
    @Override
    public void onCompletion() {
        mCurrentPosition = 0;
        if (mProgressManager != null) {
            // 播放完成，清除进度
            mProgressManager.saveProgress(mUrl, 0);
        }
        setPlayState(ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING);
        VideoPlayerConfig config = VideoViewManager.getConfig();
        if (config != null && config.mBuriedPointEvent != null) {
            // 视频播放完成
            config.mBuriedPointEvent.playerCompletion(mUrl);
        }
    }

    @Override
    public void onInfo(int what, int extra) {
        switch (what) {
            case PlayerConstant.MEDIA_INFO_BUFFERING_START:
                setPlayState(ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED);
                break;
            case PlayerConstant.MEDIA_INFO_BUFFERING_END:
                setPlayState(ConstantKeys.CurrentState.STATE_COMPLETED);
                break;
            case PlayerConstant.MEDIA_INFO_VIDEO_RENDERING_START: // 视频开始渲染
                setPlayState(ConstantKeys.CurrentState.STATE_PLAYING);
                if (mPlayerContainer.getVisibility() != VISIBLE) {
                    pause();
                }
                break;
            case PlayerConstant.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
                if (mRenderView != null)
                    mRenderView.setVideoRotation(extra);
                break;
        }
    }

    /**
     * 视频缓冲完毕，准备开始播放时回调
     */
    @Override
    public void onPrepared() {
        setPlayState(ConstantKeys.CurrentState.STATE_PREPARED);
        if (mCurrentPosition > 0) {
            seekTo(mCurrentPosition);
        }
    }

    /**
     * 获取当前播放器的状态
     *
     * @return return
     */
    public int getCurrentPlayerState() {
        return mCurrentPlayerState;
    }

    /**
     * 获取当前的播放状态
     *
     * @return return
     */
    public int getCurrentPlayState() {
        return mCurrentPlayState;
    }

    /**
     * 获取缓冲速度
     *
     * @return return
     */
    @Override
    public long getTcpSpeed() {
        return mMediaPlayer != null ? mMediaPlayer.getTcpSpeed() : 0;
    }

    /**
     * 设置播放速度
     *
     * @param speed speed
     */
    @Override
    public void setSpeed(float speed) {
        if (isInPlaybackState()) {
            mMediaPlayer.setSpeed(speed);
        }
    }

    /**
     * 获取倍速速度
     *
     * @return 速度
     */
    @Override
    public float getSpeed() {
        if (isInPlaybackState()) {
            return mMediaPlayer.getSpeed();
        }
        return 1f;
    }

    /**
     * 设置视频地址
     *
     * @param url url
     */
    @Override
    public void setUrl(String url) {
        setUrl(url, null);
    }

    /**
     * 获取视频地址
     *
     * @return return
     */
    @Override
    public String getUrl() {
        return this.mUrl;
    }

    /**
     * 设置包含请求头信息的视频地址
     *
     * @param url 视频地址
     * @param headers 请求头
     */
    public void setUrl(String url, Map<String, String> headers) {
        mAssetFileDescriptor = null;
        mUrl = url;
        mHeaders = headers;
        VideoPlayerConfig config = VideoViewManager.getConfig();
        if (config != null && config.mBuriedPointEvent != null) {
            // 相当于进入了视频页面
            config.mBuriedPointEvent.playerIn(url);
        }
    }

    /**
     * 用于播放assets里面的视频文件
     *
     * @param fd fd
     */
    public void setAssetFileDescriptor(RawFileDescriptor fd) {
        mUrl = null;
        this.mAssetFileDescriptor = fd;
    }

    /**
     * 设置音量 0.0f-1.0f 之间
     *
     * @param v1 左声道音量
     * @param v2 右声道音量
     */
    public void setVolume(float v1, float v2) {
        if (mMediaPlayer != null) {
            mMediaPlayer.setVolume(v1, v2);
        }
    }

    /**
     * 设置进度管理器，用于保存播放进度
     *
     * @param progressManager progressManager
     */
    public void setProgressManager(ProgressManager progressManager) {
        this.mProgressManager = progressManager;
    }

    /**
     * 循环播放， 默认不循环播放
     *
     * @param looping looping
     */
    public void setLooping(boolean looping) {
        mIsLooping = looping;
        if (mMediaPlayer != null) {
            mMediaPlayer.setLooping(looping);
        }
    }

    /**
     * 自定义播放核心，继承{@link PlayerFactory}实现自己的播放核心
     *
     * @param playerFactory playerFactory
     */
    public void setPlayerFactory(PlayerFactory<P> playerFactory) {
        if (playerFactory == null) {
            throw new VideoException(VideoException.CODE_NOT_PLAYER_FACTORY, "PlayerFactory can not be null!");
        }
        mPlayerFactory = playerFactory;
    }

    /**
     * 自定义RenderView，继承{@link SurfaceFactory}实现自己的RenderView
     *
     * @param renderViewFactory renderViewFactory
     */
    public void setRenderViewFactory(SurfaceFactory renderViewFactory) {
        if (renderViewFactory == null) {
            throw new VideoException(VideoException.CODE_NOT_RENDER_FACTORY, "RenderViewFactory can not be null!");
        }
        mRenderViewFactory = renderViewFactory;
    }

    /**
     * 进入全屏
     */
    @Override
    public void startFullScreen() {
        if (mIsFullScreen) {
            return;
        }
        ComponentContainer decorView = componentContainer;
        mIsFullScreen = true;

        setPlayerState(ConstantKeys.PlayMode.MODE_FULL_SCREEN);
        refreshSurface(); // 新增：刷新surfaceView，避免画面比例不正确
        // 隐藏NavigationBar和StatusBar
        VideoPlayerHelper.instance().hideSysBar(decorView, mContext, mVideoController);
        if (decorView == null) {
            return;
        }
        // 从当前FrameLayout中移除播放器视图
        this.removeComponent(mPlayerContainer);
        // 将播放器视图添加到DecorView中即实现了全屏
        decorView.addComponent(mPlayerContainer);
    }

    /**
     * 设置decorView， 全屏功能需要用到
     *
     * @param decorView decorView
     */
    public void setDecorView(ComponentContainer decorView) {
        this.componentContainer = decorView;
    }

    /**
     * 退出全屏后， 刷新surfaceView
     */
    public void refreshSurface() {
        if (mRenderView != null) {
            mRenderView.setScaleType(ConstantKeys.PlayerScreenScaleType.SCREEN_SCALE_ORIGINAL);
            new EventHandler(EventRunner.getMainEventRunner()).postTask(new Runnable() {
                @Override
                public void run() {
                    if (mRenderView != null) {
                        mRenderView.setScaleType(mCurrentScreenScaleType);
                    }
                }
            }, 100);
        }
    }

    /**
     * 退出全屏
     */
    @Override
    public void stopFullScreen() {
        if (!mIsFullScreen) {
            return;
        }
        mIsFullScreen = false;
        if (mVideoController.getFullScreenButton() != null) {
            mVideoController.getFullScreenButton().setSelected(false);
        }
        setPlayerState(ConstantKeys.PlayMode.MODE_NORMAL);
        // 新增：刷新surfaceView，避免画面比例不正确
        refreshSurface();
        ComponentContainer decorView = componentContainer;
        // 显示NavigationBar和StatusBar
        VideoPlayerHelper.instance().showSysBar(decorView, mContext, mVideoController);
        if (decorView == null) {
            return;
        }

        // 把播放器视图从DecorView中移除并添加到当前FrameLayout中即退出了全屏
        decorView.removeComponent(mPlayerContainer);
        this.addComponent(mPlayerContainer);
    }

    /**
     * 判断是否处于全屏状态
     *
     * @return return
     */
    @Override
    public boolean isFullScreen() {
        return mIsFullScreen;
    }

    /**
     * 开启小屏
     */
    public void startTinyScreen() {
        if (mIsTinyScreen) {
            return;
        }
        ComponentContainer contentView = VideoPlayerHelper.instance().getContentView(mContext, mVideoController);
        if (contentView == null) {
            return;
        }
        this.removeComponent(mPlayerContainer);
        int width = mTinyScreenSize[0];
        if (width <= 0) {
            width = PlayerUtils.getScreenWidth(getContext(), false) / 2;
        }
        int height = mTinyScreenSize[1];
        if (height <= 0) {
            height = width * 9 / 16;
        }
        LayoutConfig params = new LayoutConfig(width, height);
        params.alignment = LayoutAlignment.BOTTOM | LayoutAlignment.END;
        contentView.addComponent(mPlayerContainer, params);
        mIsTinyScreen = true;
        setPlayerState(ConstantKeys.PlayMode.MODE_TINY_WINDOW);
    }

    /**
     * 3.2 4.1开启小屏
     *
     * @param contentView contentView
     */
    public void startTinyScreen(ComponentContainer contentView) {
        if (mIsTinyScreen) {
            return;
        }
        if (contentView == null) {
            return;
        }
        this.removeComponent(mPlayerContainer);
        int width = mTinyScreenSize[0];
        if (width <= 0) {
            width = PlayerUtils.getScreenWidth(getContext(), false) / 2;
        }
        int height = mTinyScreenSize[1];
        if (height <= 0) {
            height = width * 9 / 16;
        }
        LayoutConfig params = new LayoutConfig(width, height);
        params.alignment = LayoutAlignment.BOTTOM | LayoutAlignment.END;
        contentView.addComponent(mPlayerContainer, params);
        mIsTinyScreen = true;
        setPlayerState(ConstantKeys.PlayMode.MODE_TINY_WINDOW);
        refreshSurface();
    }

    /**
     * 退出小屏
     *
     * @param container container
     */
    public void stopTinyScreen(ComponentContainer container) {
        if (!mIsTinyScreen) {
            return;
        }
        if (container == null) {
            return;
        }
        container.removeComponent(mPlayerContainer);
        LayoutConfig params = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            ComponentContainer.LayoutConfig.MATCH_PARENT);
        this.addComponent(mPlayerContainer, params);
        mIsTinyScreen = false;
        setPlayerState(ConstantKeys.PlayMode.MODE_NORMAL);
    }

    /**
     * 退出小屏
     */
    public void stopTinyScreen() {
        if (!mIsTinyScreen) {
            return;
        }
        ComponentContainer contentView = VideoPlayerHelper.instance().getContentView(mContext, mVideoController);
        if (contentView == null) {
            return;
        }
        contentView.removeComponent(mPlayerContainer);
        LayoutConfig params = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            ComponentContainer.LayoutConfig.MATCH_PARENT);
        this.addComponent(mPlayerContainer, params);
        mIsTinyScreen = false;
        setPlayerState(ConstantKeys.PlayMode.MODE_NORMAL);
    }

    /**
     * 是否是小窗口模式
     *
     * @return 是否是小窗口模式
     */
    public boolean isTinyScreen() {
        return mIsTinyScreen;
    }

    @Override
    public void onVideoSizeChanged(int videoWidth, int videoHeight) {
        mVideoSize[0] = videoWidth;
        mVideoSize[1] = videoHeight;
        if (mRenderView != null) {
            mRenderView.setScaleType(mCurrentScreenScaleType);
            mRenderView.setVideoSize(videoWidth, videoHeight);
        }
    }

    /**
     * 设置视频比例
     *
     * @param screenScaleType screenScaleType
     */
    @Override
    public void setScreenScaleType(@ConstantKeys.ScreenScaleType int screenScaleType) {
        mCurrentScreenScaleType = screenScaleType;
        if (mRenderView != null) {
            mRenderView.setScaleType(screenScaleType);
        }
    }

    /**
     * 设置镜像旋转，暂不支持SurfaceView
     *
     * @param enable enable
     */
    @Override
    public void setMirrorRotation(boolean enable) {
        if (mRenderView != null) {
            mRenderView.getView().setScaleX(enable ? -1 : 1);
        }
    }

    /**
     * 截图，暂不支持SurfaceView
     *
     * @return return
     */
    @Override
    public PixelMapElement doScreenShot() {
        if (mRenderView != null) {
            return mRenderView.doScreenShot();
        }
        return null;
    }

    /**
     * 获取视频宽高,其中width: mVideoSize[0], height: mVideoSize[1]
     *
     * @return return
     */
    @Override
    public int[] getVideoSize() {
        return mVideoSize.clone();
    }

    /**
     * 旋转视频画面
     *
     * @param rotation 角度
     */
    @Override
    public void setRotation(float rotation) {
        if (mRenderView != null) {
            mRenderView.setVideoRotation((int) rotation);
        }
    }

    /**
     * 向Controller设置播放状态，用于控制Controller的ui展示
     * 这里使用注解限定符，不要使用1，2这种直观数字，不方便知道意思
     * 播放状态，主要是指播放器的各种状态
     * -1 播放错误
     * 0 播放未开始
     * 1 播放准备中
     * 2 播放准备就绪
     * 3 正在播放
     * 4 暂停播放
     * 5 正在缓冲(播放器正在播放时，缓冲区数据不足，进行缓冲，缓冲区数据足够后恢复播放)
     * 6 暂停缓冲(播放器正在播放时，缓冲区数据不足，进行缓冲，此时暂停播放器，继续缓冲，缓冲区数据足够后恢复暂停
     * 7 播放完成
     * 8 开始播放中止
     *
     * @param playState playState
     */
    protected void setPlayState(@ConstantKeys.CurrentStateType int playState) {
        mCurrentPlayState = playState;
        if (mVideoController != null) {
            mVideoController.setPlayState(playState);
        }
        if (mOnStateChangeListeners != null) {
            for (OnVideoStateListener l : PlayerUtils.getSnapshot(mOnStateChangeListeners)) {
                if (l != null) {
                    l.onPlayStateChanged(playState);
                }
            }
        }
    }

    /**
     * 向Controller设置播放器状态，包含全屏状态和非全屏状态
     * 播放模式
     * 普通模式，小窗口模式，正常模式三种其中一种
     * MODE_NORMAL 普通模式
     * MODE_FULL_SCREEN 全屏模式
     * MODE_TINY_WINDOW 小屏模式
     *
     * @param playerState playerState
     */
    protected void setPlayerState(@ConstantKeys.PlayModeType int playerState) {
        mCurrentPlayerState = playerState;
        if (mVideoController != null) {
            mVideoController.setPlayerState(playerState);
        }
        if (mOnStateChangeListeners != null) {
            for (OnVideoStateListener l : PlayerUtils.getSnapshot(mOnStateChangeListeners)) {
                if (l != null) {
                    l.onPlayerStateChanged(playerState);
                }
            }
        }
    }

    /**
     * 添加一个播放状态监听器，播放状态发生变化时将会调用
     *
     * @param listener listener
     */
    public void addOnStateChangeListener(OnVideoStateListener listener) {
        if (mOnStateChangeListeners == null) {
            mOnStateChangeListeners = new ArrayList<>();
        }
        mOnStateChangeListeners.add(listener);
    }

    /**
     * 移除某个播放状态监听
     *
     * @param listener listener
     */
    public void removeOnStateChangeListener(OnVideoStateListener listener) {
        if (mOnStateChangeListeners != null) {
            mOnStateChangeListeners.remove(listener);
        }
    }

    /**
     * 设置一个播放状态监听器，播放状态发生变化时将会调用，
     * 如果你想同时设置多个监听器，推荐 {@link #addOnStateChangeListener(OnVideoStateListener)}。
     *
     * @param listener listener
     */
    public void setOnStateChangeListener(OnVideoStateListener listener) {
        if (mOnStateChangeListeners == null) {
            mOnStateChangeListeners = new ArrayList<>();
        } else {
            mOnStateChangeListeners.clear();
        }
        mOnStateChangeListeners.add(listener);
    }

    /**
     * 移除所有播放状态监听
     */
    public void clearOnStateChangeListeners() {
        if (mOnStateChangeListeners != null) {
            mOnStateChangeListeners.clear();
        }
    }

    /**
     * 改变返回键逻辑，用于activity
     *
     * @return return
     */
    public boolean onBackPressed() {
        return mVideoController != null && mVideoController.onBackPressed();
    }

    /*-----------------------------暴露api方法--------------------------------------**/
    /*-----------------------------暴露api方法--------------------------------------**/

    public void setVideoBuilder(VideoPlayerBuilder videoBuilder) {
        if (mPlayerContainer == null || videoBuilder == null) {
            return;
        }
        // 设置视频播放器的背景色
        ShapeElement background = new ShapeElement();
        background.setRgbColor(new RgbColor(videoBuilder.mColor.getValue()));
        mPlayerContainer.setBackground(background);
        // 设置小屏的宽高
        if (videoBuilder.mTinyScreenSize != null && videoBuilder.mTinyScreenSize.length > 0) {
            mTinyScreenSize = videoBuilder.mTinyScreenSize;
        }
        // 一开始播放就seek到预先设置好的位置
        if (videoBuilder.mCurrentPosition > 0) {
            this.mCurrentPosition = videoBuilder.mCurrentPosition;
        }
        // 是否开启AudioFocus监听， 默认开启
        this.mEnableAudioFocus = videoBuilder.mEnableAudioFocus;
    }
}
